<?php 

// ---------------------------------------------
// -----------    加载       -----------

function L($type, $name) {
    if(!in_array($type, ['model', 'logic'])) {
        throw new Exception("系统内部错误：L函数加载器类型有误", 1);
    }
    static $loaded = [
        'model' => [],
        'common_model' => false,
        'logic' => [],
        'common_logic' => false
    ];

    $classObject = $loaded[$type][$name];
    if(!empty($classObject)) {
        return $classObject;
    }

    global $_W;
    $commonfile = MROOT. "/szxh/{$type}/Common.php";
    $logicfile  = MROOT. "/szxh/{$type}/{$name}.php";

    $namespaceName = str_replace('/', '\\', $name);
    $className  = "szxh\\{$type}\\{$namespaceName}";

    if(!$loaded["common_". $type] && file_exists($commonfile)) {
        include $commonfile;
        $loaded["common_". $type] = true;
    }

    if(!file_exists($logicfile)) {
        throw new Exception("{$logicfile} 文件未找到", 1);
    }
    include $logicfile;

    if(!class_exists($className)) {
        throw new Exception("class {$className} 未找到", 1);
    }
    $class = new $className();
    $loaded[$type][$name] = $class;
    return $class;
}

/**
 * 类似tp的model函数
 */
function model($name = '') {
    static $modelObj;
    if(empty($name) && !empty($modelObj)) {
        return $modelObj;
    }
    $modelObj = L('model', $name);
    return $modelObj;
}

function logic($name = '') {
    static $logicObj;
    if(empty($name) && !empty($logicObj)) {
        return $logicObj;
    }
    $logicObj = L('logic', $name);
    return $logicObj;
}

/**
 * 保证当前状态为正常状态，否则执行对应的处理
 * @param  string $name 执行状态名称
 * @param  any $any 执行对应状态需要的参数，从第二个参数起一直往后
 * @return [type]       [description]
 */
function guard($name = '') {
    static $class = null;
    $params = func_get_args();
    array_shift($params);
    if(empty($class)) {
        $class = new \szxh\Guard();
    }
    if(!method_exists($class, $name)) {
        throw new Exception("guard(\$name) \$name={$name} is not defined", 1);
    }
    return call_user_func_array([$class, $name], $params);
}

function vendor($class) {

    static $vendor = [];

    // 连接过的文件直接返回正常实例前的名字
    if(!empty($vendor[$class])) {
        return $vendor[$class];
    }

    $filename = MFRAME. "/vendor/{$class}.class.php";

    if(!file_exists($filename)) {
        throw new Exception("{$filename}文件未找到", 1);
        
    }

    include MFRAME. "/vendor/{$class}.php";

    $classname = 'szxh\\'. str_replace('/', '\\', $class);

    if(!class_exists($classname)) {
        throw new Exception("{$classname}不存在", 1);
    }

    $vendor[$class] = $classname;

    return $classname;

}

// ---------------------------------------------
// ---------------------------------------------



// ---------------------------------------------
// ----------     地址         ------------

/**
 * 获取主域名
 */
function domain($servername) {
    $server = array_reverse(explode('.', $servername));
    return $server[1]. '.'. $server[0]; // domain.com
}
/**
 * 获取实际访问的主机名
 */
function servername($scheme = false) {
    $hostname = $_SERVER['HTTP_HOST'];
    if($scheme) {
        $hostname = scheme() . $hostname;
    }
    return $hostname;
}
function scheme() {
    return $_SERVER['REQUEST_SCHEME'] ? $_SERVER['REQUEST_SCHEME'] .'://' : 'http://';
}
function wxref($url) {
    if(strpos($url, 'wxref=mp.weixin.qq.com') !== false && strpos($url, '#wechat_redirect') === false) {
        $url .= '#wechat_redirect';
    }
    return $url;
}

/**
 * 当前域名地址，默认为当前访问地址
 * $params必须为数组
 * $use_gets是否使用$_GET参数
 */
function address($params = [], $use_gets = true) {
    if($use_gets) {
        $params = array_merge($_GET, $params);
    }
    return $_W['script_name'] . '?' . http_build_query($params);
}

/**
 * $_GET 所有参数转换为地址栏字符串形式
 */
function get_query($get) {
    return wxref(http_build_query($get));
}

/**
 * 网站自定义跳转，在当前子模块中跳转
 */
function aurl($params = [], $eid = false) {

    global $_W, $_GPC;

    if(is_string($params) || is_numeric($params)) {
        $params = ['et'=> $params];
    }

    $params = array_merge([
        'eid' => $eid ?: $_GPC['eid'],
        'version_id' => $_GPC['version_id']
    ], $params);

    return url('site/entry', $params);

}

/**
 * 手机自定义跳转，在当前子模块中跳转
 */
function purl($do, $query = [], $noredirect = true) {
    global $_W;
    unset($query['i']);
    unset($query['c']);
    $query['do'] = $do;
    $query['m'] = strtolower(MNAME);
    return murl('entry', $query, $noredirect);
}

/**
 * 跳转至其他链接
 * 建议配合aurl和purl使用
 */
function tolink($url) {
    header("location: " . $url, true);
    exit;
}

/**
 * 从微擎后台生成可在app端查看的指定页面
 * $do 跳转app.inc
 * $params 自定义参数
 */
function web2app_url($do, $params = []) {
    global $_W;
    $modelurl = purl($do, $params);

    $p = explode('?', $modelurl, 2);

    if(count($p) < 2) {
        array_unshift($p, '');
    }

    $scriptName = str_replace('web', 'app', $_SERVER['SCRIPT_NAME']);

    return servername(true).$scriptName.'?'. $p[1];
}


// ---------------------------------------------
// ---------------------------------------------


// -------------------------------------------
// --------------    数据结构   -------------

/**
 * Important:
 * 获取多选的名称分组，支持使用 , ; | / 拆分
 * @param  string $keys [description]
 * @return [type]       [description]
 */
function get_keys_array($keys = '') {
    if(is_array($keys)) {
        return $keys;
    }
    return preg_split('/[,;|\/]+/', trim($keys));
}

/**
 * 驼峰法转小写下划线命名 
 * @param  [type]  $str  [description]
 * @return [type]        [description]
 */
function camelToLower($str = '') {
    return strtolower(preg_replace('/((?<=[a-z])(?=[A-Z]))/', '_', $str)); break;
}

/**
 * 驼峰法转大写下划线命名 
 * @param  [type]  $str  [description]
 * @return [type]        [description]
 */
function camelToUpper($str = '') {
    return strtoupper(preg_replace('/((?<=[a-z])(?=[A-Z]))/', '_', $str)); break;
}


// -------------------------------------------
// -------------------------------------------


// -------------------------------------------
// --------------   时间    ---------------

/**
 * 获取时间上下限时间戳数组，参数2为时间戳，默认为当前时间
 * 参数1： 1当天  2本月  3今年
 * timestring 最好传日期格式，传时间戳容易出问题
 */
function is_time($type = 1, $timeString = 0) {
    if($timeString === false) {
        return [
            "start" => false,
            "end"   => false
        ];
    }
    if(strtotime($timeString) === false) {
        if (!(is_numeric($timeString) && 0 < $timeString)) {$timeString = $_SERVER['REQUEST_TIME'];}
    } else {
        $timeString = strtotime($timeString);
    }
    $timeArray = array();
    switch ($type) {
        case 1://当天日期范围
            $timeArray['start'] = strtotime(date('Y-m-d 00:00:00', $timeString));
            $timeArray['end'] = $timeArray['start']+3600*24-1;
            break;
        case 2://当月日期范围
            $timeArray['start'] = strtotime(date('Y-m-01 00:00:00', $timeString));
            $timeArray['end'] = $timeArray['start']+3600*24*date('t', $timeString)-1;
            break;
        case 3://当年日期范围
            $timeArray['start'] = strtotime(date('Y-01-01 00:00:00', $timeString));
            $timeArray['end'] = $timeArray['start']+(!!date('L', $timeString)?366:365)*3600*24-1;
            break;
    }
    return $timeArray;
}

/**
 * true：获取毫秒表示时间字符串
 * 默认：毫秒时间戳
 * @return string
 */
function get_microtime($boolean = false) {
    // $microtime = microtime();
    // $microtime = explode(' ', $microtime);
    // $mic  = substr($microtime[0], 2, 3);  //毫秒
    // if($boolean) {
    //  $time = date('His', $microtime[1]);  //时间
    // } else {
    //  $time = $microtime[1];
    // }
    $microtime = $_SERVER['REQUEST_TIME_FLOAT'];
    $microtime = explode('.', $microtime);
    $mic = $microtime[1];
    while(strlen($mic) < 4) {
        $mic = '0'.$mic;
    }
    if($boolean) {
        $time = date('His', $microtime[0]);
    } else {
        $time = $microtime[0];
    }
    return $time.$mic;
}

// -------------------------------------------
// -------------------------------------------


// -------------------------------------------
// ------------   数据验证   -----------


function is($value, $rule, $data = []) {
    switch ($rule) {
        case 'require':
            // 必须
            $result = !empty($value) || '0' == $value;
            break;
        case 'accepted':
            // 接受
            $result = in_array($value, ['1', 'on', 'yes']);
            break;
        case 'date':
            // 是否是一个有效日期
            $result = false !== strtotime($value);
            break;
        case 'alpha':
            // 只允许字母
            $result = regex($value, '/^[A-Za-z]+$/');
            break;
        case 'alphaNum':
            // 只允许字母和数字
            $result = regex($value, '/^[A-Za-z0-9]+$/');
            break;
        case 'alphaDash':
            // 只允许字母、数字和下划线 破折号
            $result = regex($value, '/^[A-Za-z0-9\-\_]+$/');
            break;
        case 'chs':
            // 只允许汉字
            $result = regex($value, '/^[\x{4e00}-\x{9fa5}]+$/u');
            break;
        case 'chsAlpha':
            // 只允许汉字、字母
            $result = regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u');
            break;
        case 'chsAlphaNum':
            // 只允许汉字、字母和数字
            $result = regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9]+$/u');
            break;
        case 'chsDash':
            // 只允许汉字、字母、数字和下划线_及破折号-
            $result = regex($value, '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9\_\-]+$/u');
            break;
        case 'activeUrl':
            // 是否为有效的网址
            $result = checkdnsrr($value);
            break;
        case 'ip':
            // 是否为IP地址
            $result = filter($value, [FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6]);
            break;
        case 'url':
            // 是否为一个URL地址
            $result = filter($value, FILTER_VALIDATE_URL);
            break;
        case 'float':
            // 是否为float
            $result = filter($value, FILTER_VALIDATE_FLOAT);
            break;
        case 'number':
            $result = is_numeric($value);
            break;
        case 'integer':
            // 是否为整型
            $result = filter($value, FILTER_VALIDATE_INT);
            break;
        case 'email':
            // 是否为邮箱地址
            $result = filter($value, FILTER_VALIDATE_EMAIL);
            break;
        case 'boolean':
            // 是否为布尔值
            $result = in_array($value, [true, false, 0, 1, '0', '1'], true);
            break;
        case 'array':
            // 是否为数组
            $result = is_array($value);
            break;
        case 'file':
            $result = $value instanceof File;
            break;
        case 'image':
            $result = $value instanceof File && in_array(getImageType($value->getRealPath()), [1, 2, 3, 6]);
            break;
        case 'token':
            $result = token($value, '__token__', $data);
            break;
        case 'id':
            // 单个ID
            $result = regex($value, '/^[1-9][0-9]*$/');
            break;
        case 'ids':
            // ID序列
            $result = regex($value, '/^[1-9][0-9]*(,[1-9][0-9]*)*$/');
            break;
        case 'mobile':
            // 手机号
            $result = regex($value, '/^0?(1[0-9][0-9])[0-9]{8}$/');
            break;
        case 'email':
            // 邮箱
            $result = regex($value, '/[\\w!#$%&\'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&\'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?/');
            break;
        case 'qq':
            // qq
            $result = regex($value, '/^\d{5,10}$/');
            break;
        case 'password':
            // 登录密码
            $result = regex($value, '/^(?=.*\\d)(?=.*[a-zA-Z]).{6,16}$/');
            break;
        case 'price':
            // 价格数字字符串，可以为负
            $result = regex($value, '/^(\-)?\d+(\.\d{0,2})?$/');
            break;
        default:
            // 正则验证
            $result = regex($value, $rule);
    }
    return $result;
}

function regex($name, $rule) {
    if (0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) {
        // 不是正则表达式则两端补上/
        $rule = '/^' . $rule . '$/';
    }
    return 1 === preg_match($rule, (string) $name);
}

function filter($value, $rule) {
    if (is_string($rule) && strpos($rule, ',')) {
        list($rule, $param) = explode(',', $rule);
    } elseif (is_array($rule)) {
        $param = isset($rule[1]) ? $rule[1] : null;
        $rule  = $rule[0];
    } else {
        $param = null;
    }
    return false !== filter_var($value, is_int($rule) ? $rule : filter_id($rule), $param);
}

// -------------------------------------------
// -------------------------------------------


// -------------------------------------------
// --------------  信息   -----------------


/**
 * 获取用户信息
 * 当$openid为true时获取当前打开页面的用户信息
 */
function userinfo($openid = true) {
    global $_W;
    if($openid === true) {
        return $_W['fans'] ?: false;
    }
    if($_W['fans']['openid'] == $openid) {
        return $_W['fans']['tag'] ?: false;
    }
    return mc_fansinfo($openid)['tag'] ?: false;
}

/**
 * 返回是否是操作员
 * Tips：微擎后台权限分站长、管理员和操作员(clerk)
 */
function isclerk() {
    global $_W;

    if($_W['role'] != 'clerk') {
        return false;
    }

    return true;
}


// -------------------------------------------
// -------------------------------------------




// -------------------------------------------
// ----------------  其他   ----------------

/**
 * 导出excel表格
 *
 * @param String $fileName 文件名
 * @param String $headname 标题名
 * @param Array $headArr   表头数组
 * @param Array-Array $data 数据二维数组
 * @return void
 */
function getExcel($fileName, $headname, $headArr, $data) {

    load()->library('phpexcel/PHPExcel');
    load()->library('phpexcel/PHPExcel/Writer/Excel2007');
    load()->library('phpexcel/PHPExcel/Writer/Excel5');
    load()->library('phpexcel/PHPExcel/IOFactory');

    if(empty($data) || !is_array($data)){
        echo "当前数据不能导出，或不存在数据";
        exit;
    }
    if(empty($fileName)){
        echo "文件名不能为空";
        exit;
    }
 
    // 重新定义文件名 
    $date = date("Y_m_d",time());
    $fileName .= "_{$date}.xlsx";

    //创建新的PHPExcel对象 
    $objPHPExcel = new \PHPExcel();
    $objProps = $objPHPExcel->getProperties();
    
    //设置活动单指数到第一个表,所以Excel打开这是第一个表
    $objPHPExcel->setActiveSheetIndex(0);

    $row = 1;
    if(!empty($headname)) {
        $row++;
    }

    //设置表头
    $key = ord("A");

    $objActSheet = $objPHPExcel->getActiveSheet();

    // 设置第一行标题
    // 设置合并宽度
    $headspan = ord('A');
    $headspan += count($headArr) - 1;
    $headspan = chr($headspan);
    // 合并第一行
    $objActSheet->mergeCells('A1:'.$headspan.'1');
    // 设置第一行文字
    $objActSheet->setCellValue('A1', $headname);
    // 第一行加粗
    $objActSheet->getStyle('A1')->getFont()->setBold(true);
    // 获取第一行对齐方式
    $objAlignA5 = $objActSheet->getStyle('A1')->getAlignment();
    // 第一行文字居中
    $objAlignA5->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);

    // 加载表头
    foreach($headArr as $v){
        $colum = chr($key);
        // 设置表头值
        $objPHPExcel->setActiveSheetIndex(0)->setCellValue($colum.$row, $v);
        // 设置表头样式 - 设置成文本格式
        $objActSheet->getStyle($colum)->getNumberFormat()->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
        // 设置表头样式 - 设置成粗体
        $objActSheet->getStyle($colum.$row)->getFont()->setBold(true);
        $key += 1;
    }

    // 从第二行开始写入数据
    $column = $row + 1;
    // 写入数据
    foreach($data as $key => $rows) { //行写入
        $span = ord("A");
        foreach($rows as $keyName=>$value) {// 列写入
            $j = chr($span);
            $objActSheet->setCellValue($j.$column, $value);
            $span++;
        }
        $column++;
    }

    // 修改文字编码
    $filename = iconv("utf-8", "gb2312", $filename);
    // $sheetname = iconv("utf-8", "gb2312", $sheetname);

    //重命名表
    // $objPHPExcel->getActiveSheet()->setTitle($sheetname);

    

    //将输出重定向到一个客户端web浏览器(Excel2007)
    ob_clean();
    // header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    // header("Content-Disposition: attachment; filename=\"$fileName\"");
    // header('Cache-Control: max-age=0');
    // $objWriter = new PHPExcel_Writer_Excel5($objPHPExcel);
    header('Pragma:public');
    header('Expires:0');
    header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
    header('Content-Type:application/force-download');
    header('Content-Type:application/vnd.ms-excel');
    header('Content-Type:application/octet-stream');
    header('Content-Type:application/download');
    header("Content-Disposition: attachment; filename=\"$fileName\"");
    header('Content-Transfer-Encoding:binary');
    $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
    $objWriter->save('php://output'); //文件通过浏览器下载
    exit;

}

function output_qrcode($string) {
    ob_clean();
    load()->library('qrcode');
    echo Qrcode::png($string);
}



function getTableName($name, $addon = false) {
    if(empty($addon)) {
        $addon = MPREFIX;
    } else {
        $addon .= '_';
    }
    return $addon. camelToLower($name);
}

function getSystemTableName($name, $addon = false) {
    if(empty($addon)) {
        $addon = M_SYSTEN_PREFIX;
    } else {
        $addon .= '_';
    }
    return $addon. camelToLower($name);
}

function register_jweixin($debug = false) {
    
    $agent = $_SERVER['HTTP_USER_AGENT'];

    preg_match("/MicroMessenger\\/(\\w+\\.\\w+\\.\\w+)[\\s\\S]/", $agent, $agentres);

    if(empty($agentres)) {
        register_jssdk($debug);
        return 0;
    }

    $version = str_replace('.', '', $agentres[1]);

    // 老版本微信
    if($version < 672) {
        register_jssdk($debug);
        return $version;
    }

    global $_W;
    
    if (defined('HEADER')) {
        echo '';
        return;
    }
    
    $sysinfo = array(
        'uniacid'   => $_W['uniacid'],
        'acid'      => $_W['acid'],
        'siteroot'  => $_W['siteroot'],
        'siteurl'   => $_W['siteurl'],
        'attachurl' => $_W['attachurl'],
        'cookie'    => array('pre'=>$_W['config']['cookie']['pre'])
    );
    if (!empty($_W['acid'])) {
        $sysinfo['acid'] = $_W['acid'];
    }
    if (!empty($_W['openid'])) {
        $sysinfo['openid'] = $_W['openid'];
    }
    if (defined('MODULE_URL')) {
        $sysinfo['MODULE_URL'] = MODULE_URL;
    }
    $sysinfo = json_encode($sysinfo);
    $jssdkconfig = json_encode($_W['account']['jssdkconfig']);
    $debug = $debug ? 'true' : 'false';
    
    $script = <<<EOF

<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script type="text/javascript">
    window.sysinfo = window.sysinfo || $sysinfo || {};
    
    // jssdk config 对象
    jssdkconfig = $jssdkconfig || {};
    
    // 是否启用调试
    jssdkconfig.debug = $debug;
    
    jssdkconfig.jsApiList = [
        'checkJsApi',
        'onMenuShareTimeline',
        'onMenuShareAppMessage',
        'onMenuShareQQ',
        'onMenuShareWeibo',
        'hideMenuItems',
        'showMenuItems',
        'hideAllNonBaseMenuItem',
        'showAllNonBaseMenuItem',
        'translateVoice',
        'startRecord',
        'stopRecord',
        'onRecordEnd',
        'playVoice',
        'pauseVoice',
        'stopVoice',
        'uploadVoice',
        'downloadVoice',
        'chooseImage',
        'previewImage',
        'uploadImage',
        'downloadImage',
        'getNetworkType',
        'openLocation',
        'getLocation',
        'hideOptionMenu',
        'showOptionMenu',
        'closeWindow',
        'scanQRCode',
        'chooseWXPay',
        'openProductSpecificView',
        'addCard',
        'chooseCard',
        'openCard',
        'updateAppMessageShareData',
        'updateTimelineShareData'
    ];
    
    wx.config(jssdkconfig);
    
</script>
EOF;
    echo $script;
    return $version;
}